#install.packages("knitr")
Warning message:
Unknown or uninitialised column: `Country`.
#install.packages("grid")
#install.packages("MLRMPA")
#install.packages("dprep")
#install.packages("normalr")
#install.packages("ggcorrplot")
#install.packages("RColorBrewer")
#install.packages("rgdal")
#install.packages("jsonlite")
#install.packages("plotly")
library(gridExtra)
library(dplyr)
library(lubridate)
library(magrittr)
library(ggplot2)
library(tidyr)
library(knitr)
library(normalr)
library(ggcorrplot)
library(leaflet)
library(plotly)
#library(jsonlite)
#library(RColorBrewer)
#library(rgdal)
#library(wesanderson)
#library(MLRMPA)
#??src_mysql
my_db <- src_mysql(
dbname = "covid",
host = "localhost",
user = "root",
password = "1234"
)
my_db
src: mysql 8.0.21 [root@localhost:/covid]
tbls: citytemperature, covid_confirmed_yearly, covid_deaths_yearly, covid_recovered_yearly, covid19_confirmed_global, covid19_deaths_global,
covid19_recovered_global, full_datas, gdp, gdp19, gdp2019, healthranking, imf-country, owid-covid-data, population, temp2019, world_temp
##import data
df_conf <- tbl(my_db, sql("select * from covid_confirmed_yearly"))
df_conf <- as.data.frame(df_conf)
df_conf
df_deaths <- tbl(my_db, sql("select * from covid_deaths_yearly"))
df_deaths <- as.data.frame(df_deaths)
df_deaths
df_recover <- tbl(my_db, sql("select * from covid_recovered_yearly"))
df_recover <- as.data.frame(df_recover)
df_recover
##check the time frame of the data
Warning message:
Unknown or uninitialised column: `Country`.
n.col <- ncol(df_conf)
dates <- names(df_conf)[5:n.col]%>% mdy()
range(dates)
[1] "2020-01-22" "2021-01-11"
min.date <- min(dates)
max.date <- max(dates)
min.date.txt <- min.date %>% format('%d %b %Y')
max.date.txt <- max.date %>% format('%d %b %Y')
#clean data
Warning message:
Unknown or uninitialised column: `Country`.
cleanData <- function(data) {
## remove some columns
data %<>% select(-c(Province.State, Lat, Long)) %>% rename(country=Country.Region)
## convert from wide to long format
data %<>% gather(key=date, value=count, -country)
## convert from character to date
data %<>% mutate(date = date %>% mdy())
## aggregate by country
data %<>% group_by(country, date) %>% summarise(count=sum(count, na.rm=T)) %>% as.data.frame()
return(data)
}
## clean the three data sets
data.confirmed <- df_conf %>% cleanData() %>% rename(confirmed=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data.deaths <- df_deaths %>% cleanData() %>% rename(deaths=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data.recovered <- df_recover %>% cleanData() %>% rename(recovered=count)
`summarise()` regrouping output by 'country' (override with `.groups` argument)
data <- data.confirmed %>% merge(data.deaths, all=T) %>% merge(data.recovered, all=T)
data
## countries/regions with confirmed cases, excl. cruise ships
countries <- data %>% pull(country) %>% setdiff('Cruise Ship')
data
data.world <- data %>% group_by(date) %>%
summarise(country='World',
confirmed = sum(confirmed, na.rm=T),
deaths = sum(deaths, na.rm=T),
recovered = sum(recovered, na.rm=T))
`summarise()` ungrouping output (override with `.groups` argument)
data %<>% rbind(data.world)
data
data %<>% mutate(current.confirmed = confirmed - deaths - recovered)
View(data)
#World Map (with State)
Warning message:
Unknown or uninitialised column: `Country`.
#select last column,which is the number of latest confirmed cases
x <- df_conf
x
x$confirmed <- x[, ncol(x)]
x %<>% select(c(Country.Region, Province.State, Lat, Long, confirmed)) %>%
mutate(txt=paste0(Country.Region, ' - ', Province.State, ': ', confirmed))
m <- leaflet(width=1200, height=800) %>% addTiles()
# circle marker (units in pixels)
m %<>% addCircleMarkers(x$Long, x$Lat,
radius=1+log2(x$confirmed),
#radius=0.01*sqrt(x$confirmed),
stroke=F,
color='red', fillOpacity=0.3,
label = x$txt
#popup=x$txt
)
# world
m
preservee1fdc031dc6a6f95
View(lat.long)
Warning messages:
1: Unknown or uninitialised column: `Country`.
2: Unknown or uninitialised column: `Country`.
3: Unknown or uninitialised column: `Country`.
4: Unknown or uninitialised column: `Country`.
5: Unknown or uninitialised column: `Country`.
6: Unknown or uninitialised column: `Country`.
7: Unknown or uninitialised column: `Country`.
m.confirmed <- data %>%
select(country, date, confirmed) %>%
merge((lat.long %>% select(country, Lat, Long)), by = "country") %>%
arrange(country, date)
m.confirmed
#rate
data %<>% arrange(country, date)
n <- nrow(data)
day1 <- min(data$date)
data %<>% mutate(new.confirmed = ifelse(date == day1, NA, confirmed - lag(confirmed, n=1)),
new.deaths = ifelse(date == day1, NA, deaths - lag(deaths, n=1)),
new.recovered = ifelse(date == day1, NA, recovered - lag(recovered, n=1)))
data %<>% mutate(new.confirmed = ifelse(new.confirmed < 0, 0, new.confirmed),
new.deaths = ifelse(new.deaths < 0, 0, new.deaths),
new.recovered = ifelse(new.recovered < 0, 0, new.recovered))
## death rate based on total deaths and recovered cases
data %<>% mutate(rate.upper = (100 * deaths / (deaths + recovered)) %>% round(1),
rate.upper = ifelse(is.nan(rate.upper), 0, rate.upper))
## lower bound: death rate based on total confirmed cases
data %<>% mutate(rate.lower = (100 * deaths / confirmed) %>% round(1),
rate.lower = ifelse(is.nan(rate.lower), 0, rate.lower))
## death rate based on the number of death/recovered on every single day
data %<>% mutate(rate.daily = (100 * new.deaths / (new.deaths + new.recovered)) %>% round(1),
rate.daily = ifelse(is.nan(rate.daily), 0, rate.daily))
View(data)
## convert from wide to long format
data.long <- data %>%
select(c(country, date, confirmed, current.confirmed, recovered, deaths)) %>%
gather(key=type, value=count, -c(country, date))
## set factor levels to show them in a desirable order
data.long %<>% mutate(type=recode_factor(type, confirmed='Total Confirmed',
current.confirmed='Current Confirmed',
recovered='Recovered',
deaths='Deaths'))
View(data.long)
world
##Number of case World
world <- filter(data.long,country == 'World')
plot1 <- world %>% filter(type != 'Total Confirmed') %>%
ggplot(aes(x=date, y=count)) +
geom_area(aes(fill=type), alpha=0.5) +
labs(title=paste0('Numbers of Cases Worldwide - ', max.date.txt)) +
scale_fill_manual(values=c('red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1))
plot2 <- world %>%
ggplot(aes(x=date, y=count)) +
geom_line(aes(color=type)) +
labs(title=paste0('Numbers of Cases Worldwide (log scale) - ', max.date.txt)) +
scale_color_manual(values=c('purple', 'red', 'green', 'black')) +
theme(legend.title=element_blank(), legend.position='bottom',
plot.title = element_text(size=7),
axis.title.x=element_blank(),
axis.title.y=element_blank(),
legend.key.size=unit(0.2, 'cm'),
legend.text=element_text(size=6),
axis.text=element_text(size=7),
axis.text.x=element_text(angle=45, hjust=1)) +
scale_y_continuous(trans='log10')
## show two plots side by side
grid.arrange(plot1, plot2, ncol=2)

## Current Confirmed Cases
data.world <- data %>% filter(country=='World')
n <- nrow(data.world)
plot1 <- ggplot(data.world, aes(x=date, y=current.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Current Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
gly.plot1 <- ggplotly(plot1)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
plot2 <- ggplot(data.world, aes(x=date, y=new.confirmed)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Daily New Confirmed Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
gly.plot2 <- ggplotly(plot2)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'
Removed 1 rows containing non-finite values (stat_smooth).
## show two plots side by side
grid.arrange(plot1, plot2, ncol=2)

#subplot(gly.plot1, gly.plot2)
## a scatter plot with a smoothed line and vertical x-axis labels
plot1 <- ggplot(data.world, aes(x=date, y=deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot2 <- ggplot(data.world, aes(x=date, y=recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='Accumulative Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot3 <- ggplot(data.world, aes(x=date, y=new.deaths)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Deaths') +
theme(axis.text.x=element_text(angle=45, hjust=1))
plot4 <- ggplot(data.world, aes(x=date, y=new.recovered)) +
geom_point() + geom_smooth() +
xlab('') + ylab('Count') + labs(title='New Recovered Cases') +
theme(axis.text.x=element_text(angle=45, hjust=1))
## show four plots together, with 2 plots in each row
grid.arrange(plot1, plot2, plot3, plot4, nrow=2)

## convert from wide to long format, for drawing area plots
rates.long <- data %>%
select(c(country, date, rate.upper, rate.lower, rate.daily)) %>%
gather(key=type, value=count, -c(country, date))
# set factor levels to show them in a desirable order
rates.long %<>% mutate(type=recode_factor(type, rate.daily = "Daily",
rate.upper="Upper bound",
rate.lower = "Lower bound")
)
g.death <- rates.long %>% filter(country == "World") %>% rename(c("Rate" = "count", "Date" = "date", "Type" = "type")) %>%
ggplot(aes(x = Date, y = Rate)) +
labs(title=paste0("Death Cases & Death Rates"), subtitle = "Death Cases & Death Rates in Top 20 Countries (%) (2020)") +
geom_line(aes(color = Type)) +
#stat_smooth(aes(color = type))
#stat_smooth(aes(x = date, y = count), method = "lm", formula = y ~ poly(x, 21), se = FALSE) +
theme(
axis.text.x = element_text(size=12),
axis.text.y = element_text(size=12),
plot.title=element_text(size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
) +
xlab("Date") + ylab("Rates (%)")
gly.death <- ggplotly(g.death)
gly.death
preserve83b63ab27d7115c9
## ranking by confirmed cases
data.latest.all <- data %>% filter(date == max(date)) %>%
select(country, date,confirmed, new.confirmed, current.confirmed,
recovered, deaths, new.deaths, death.rate=rate.lower) %>%
mutate(ranking = dense_rank(desc(confirmed))) %>%
arrange(ranking)
View(data.latest.all)
k <- 20
## top 20 countries: 21 incl. 'World'
top.countries <- data.latest.all %>% filter(ranking <= k + 1) %>%
arrange(ranking) %>% pull(country) %>% as.character()
top.countries %>% setdiff('World') %>% print()
[1] "US" "India" "Brazil" "Russia" "United Kingdom" "France" "Turkey" "Italy"
[9] "Spain" "Germany" "Colombia" "Argentina" "Mexico" "Poland" "Iran" "South Africa"
[17] "Ukraine" "Peru" "Netherlands" "Indonesia"
data.latest <- data.latest.all %>% filter(!is.na(country)) %>%
mutate(country=ifelse(ranking <= k + 1, as.character(country), 'Others')) %>%
mutate(country=country %>% factor(levels=c(top.countries, 'Others')))
data.latest %<>% group_by(country) %>%
summarise(confirmed=sum(confirmed), new.confirmed=sum(new.confirmed),
current.confirmed=sum(current.confirmed),
recovered=sum(recovered), deaths=sum(deaths), new.deaths=sum(new.deaths)) %>%
mutate(death.rate=(100 * deaths/confirmed) %>% round(1))
`summarise()` ungrouping output (override with `.groups` argument)
data.latest
data.latest %<>% select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths, current.confirmed,recovered)) %>%
mutate(recover.rate=(100 * recovered/confirmed) %>% round(1))
data.latest
df_pop <- tbl(my_db, sql("select * from population "))
df_pop <- as.data.frame(df_pop)
df_pop <- rename(df_pop,"country"="Country")
# Add World Population
world_pop <- sum(df_pop$`Population (2020)`)
df_pop[nrow(df_pop) + 1,] = c("World", world_pop)
# Add Other Countries Population
top_pop <- filter(df_pop, df_pop$country %in% top.countries & df_pop$country != "World")
top_pop <- sum(top_pop$`Population (2020)` %>% as.numeric())
others_pop <- (world_pop - top_pop)
df_pop[nrow(df_pop) + 1,] = c("Others", others_pop)
#View(df_pop)
data.latest <- merge(x = data.latest, y = df_pop, by = "country", all.x = TRUE)
data.latest
data.latest <- rename(data.latest,"population" = "Population (2020)")
data.latest$population <- data.latest$population %>% as.numeric()
data.latest <- data.latest %>%
select(c(country, confirmed, deaths, death.rate,
new.confirmed, new.deaths,
current.confirmed, recovered, recover.rate, population)) %>%
mutate(confirm.rate = (100 * confirmed / population) %>% round(1))
data.latest
data.latest %>% mutate(death.rate=death.rate %>% format(nsmall=1) %>% paste0('%'))
NA
## convert from wide to long format, for drawing area plots
data.latest.long <- data.latest %>% filter(country!='World') %>%
gather(key=type, value=count, -country)
## set factor levels to show them with proper text and in a desirable order
data.latest.long %<>% mutate(type=recode_factor(type,
confirmed='Total Confirmed',
deaths='Total Deaths',
death.rate='Death Rate (%)',
new.confirmed='New Confirmed (compared with one day before)',
new.deaths='New Deaths (compared with one day before)',
current.confirmed='Current Confirmed',
recover.rate = 'Recover Rate(%)',
confirm.rate = 'Confirmed Rate(%)'))
#View(data.latest.long)
data.one.dem <- filter(data.latest.long,type=='Total Confirmed'
| type=='Total Deaths'
| type=='Current Confirmed')
data.two.dem <- filter(data.latest.long,type=='Death Rate (%)'
| type=='New Confirmed (compared with one day before)'
| type=='New Deaths (compared with one day before)'
| type=='Recover Rate(%)'
| type=='Confirmed Rate(%)')
data.two.dem
## bar chart
data.one.dem %>% ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~type, ncol=1, scales='free_y')

data.two.dem %>% ggplot(aes(x=country, y=count, fill=country, group=country)) +
geom_bar(stat='identity') +
geom_text(aes(label=count, y=count), size=3, vjust=0) +
xlab('') + ylab('') +
labs(title=paste0('Top 20 Countries with Most Confirmed Cases - ', max.date.txt)) +
scale_fill_discrete(name='Country', labels=aes(count)) +
theme(legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size=13),
axis.text=element_text(size=8),
axis.text.x=element_text(angle=45, hjust=1)) +
facet_wrap(~type, ncol=1, scales='free_y')

##GDP
df_gdp <- tbl(my_db, sql("select * from gdp"))
df_gdp <- as.data.frame(df_gdp)
df_gdp <- rename(df_gdp,"country"="Real GDP growth (Annual percent change)")
df_gdp <- select(df_gdp,c("country","2012","2013","2014","2015","2016","2017","2018","2019","2020","2021"))
df_gdp
df_gdp2019 <- tbl(my_db, sql("select * from gdp19"))
df_gdp2019 <- as.data.frame(df_gdp2019)
df_gdp2019
NA
#healthranking
df_healt <- tbl(my_db, sql("select * from healthranking"))
df_healt <- as.data.frame(df_healt)
df_healt <- select(df_healt,c("country","healthCareIndex"))
View(df_healt)
#temp
df_temp <- tbl(my_db, sql("select * from world_temp"))
df_temp <- as.data.frame(df_temp)
df_temp$Country[df_temp$Country == "United States"] <- "US"
df_city <- select(df_temp,c("Country","City")) %>%
rename(country=Country) %>%
rename(city=City)
numofcity <- aggregate(city ~ country, data = df_city, length)
df_temp <- select(df_temp,c("Country","Avg_Year")) %>%
rename(country=Country)
View(df_temp)
#df_temp <- data.frame(country=df_temp[,1],avg=rowMeans(df_temp[,-1]))
df_temp <- df_temp %<>% group_by(country) %>% summarise(avg_temp = mean(Avg_Year,na.rm = TRUE)%>% round(1))
`summarise()` ungrouping output (override with `.groups` argument)
df_temp
#display.brewer.all()
Warning message:
Unknown or uninitialised column: `Country`.
df_temp.all <- df_temp %>% merge(data.latest.all)
View(df_temp.all)
df_temp_top.all <- df_temp.all %>% filter(country %in% top.countries) %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
View(df_temp_top)
g_temp_top <- df_temp_top %>%
ggplot(aes(x = reorder(country, ranking), y = avg_temp, fill = avg_temp)) +
labs(title=paste0("Temperature in Top 20 countries"), subtitle = "Average Temperature in Top 20 countries with most confirmed cases (°C) (2020)") +
scale_color_gradient(low = "#93DBFF", high = "#FF7771") +
geom_text(aes(label=avg_temp, y=avg_temp), size=4, vjust=-0.5) +
geom_bar(stat = "identity", position = "dodge") +
theme(
legend.title=element_blank(),
legend.position='none',
plot.title=element_text(size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 12, hjust = 0.5),
axis.text=element_text(size=8),
axis.text.x=element_text(size = 9, angle=45, hjust=1)) +
xlab("Country") + ylab("Average Temperature")
#scale_x_discrete(name = "Country") +
#scale_y_discrete(name = "Average Temperature")
#labs(title = "Temperature in Top 20 countries", subtitle = "Temperature in Top 20 countries with most confirmed cases (°C)")
#g_temp_top
g_temp_top

#df_conf
#data.latest.all
lat.long <- rename(df_conf, "country" = "Country.Region", "city" = "Province.State") %>%
select("country", "Lat", "Long") %>%
merge(df_temp.all[c("country","confirmed", "recovered", "deaths", "avg_temp", "ranking")], by = "country") %>%
distinct(country, .keep_all = TRUE) %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
View(lat.long)
label_world <- lat.long
label_world$avg_temp <- as.numeric(label_world[, names(label_world) %in% c("avg_temp")])
label_world <- label_world %>%
mutate(txt=paste0('<b>',ranking, '</b>',
'<br/>','<b>',country, '</b>',
'<br/>', "Temperature: ",avg_temp, ' °C',
'<br/>', "Confirmed: ", confirmed,
'<br/>', "Deaths: ", deaths,
'<br/>', "Recovered: ", recovered
))
label_world$txt <- label_world$txt %>% lapply(htmltools::HTML)
label_world
label_top <- label_world %>% filter(ranking < 21)
label_top
wpal <- colorNumeric("YlOrRd", label_world$avg_temp, n = 5)
topIcon <- makeIcon("star.png",
#iconUrl = "https://static.vecteezy.com/system/resources/previews/001/189/063/non_2x/star-rounded-png.png",
iconWidth = 10, iconHeight = 10
#iconAnchorX = 20, iconAnchorY = 20
)
label_world <- label_world %>% filter(ranking > 20)
m <- leaflet(width=1200, height=800) %>% addTiles()
m %<>% addCircleMarkers(label_world$Long, label_world$Lat,
# radius=2+log2(x$confirmed),
radius=10,#*log2(m.world$avg.temp),
stroke=F,
#color='red',
color = wpal(label_world$avg_temp),
fillOpacity=0.5,
#popup=label.top$txt
label= label_world$txt,
group = "World"
) %>%
addCircleMarkers(label_top$Long, label_top$Lat,
# radius=2+log2(x$confirmed),
radius=10,#*log2(m.world$avg.temp),
stroke=F,
#color='red',
color = wpal(label_top$avg_temp),
fillOpacity=0.5,
#popup=label.top$txt
label= label_top$txt,
group = "Top 20 Countries"
) %>%
addLabelOnlyMarkers(label_top$Long, label_top$Lat, label = label_top$ranking,
labelOptions = labelOptions(noHide = TRUE, textOnly = TRUE,
direction = "head",
offset = c(5,4)),
group = "Top 20 Countries") %>%
addLegend("bottomright", pal = wpal, values = label_world$avg_temp, opacity = 1,
labFormat = labelFormat(suffix = ' °C'),
title = "Temperature") %>%
addLayersControl(
#baseGroups = c("OSM (default)", "Toner", "Toner Lite"),
overlayGroups = c("Top 20 Countries", "World"),
options = layersControlOptions(collapsed = FALSE)
)
m
preserve5328a8e2e7aa8c8a
NA
data.gdp
There were 22 warnings (use warnings() to see them)
#rank GDP
data.top.hight <- data.gdp %>%
mutate(ranking = dense_rank(desc(GDP)))
data.top.hight
k <- 15
top.gdp <- data.top.hight %>%
#filter(ranking <= k + 1) %>%
arrange(ranking)
top.gdp <- head(top.gdp,21)
data.top.low <- data.gdp %>%
mutate(ranking = dense_rank(GDP))
low.gdp.long <- data.top.low %>%
#filter(ranking <= k + 1) %>%
arrange(ranking)
#View(low.gdp.long)
low.gdp <- head(low.gdp.long,23)
top20.gdp <- data.gdp %>%
filter(country %in% top.countries & country != "World") %>%
merge(data.latest.all %>% select(country, ranking), by = "country") %>%
mutate(ranking = ranking - 1) %>%
arrange(ranking)
top.gdp
low.gdp
top20.gdp
world.gdp <- df_gdp %>%
There were 17 warnings (use warnings() to see them)
filter(country == "World") %>%
gather(key = Year, value = GDP, -country)
world.gdp$group <- cut(world.gdp$GDP,c(-Inf,0,Inf),labels = c("-","+"))
g.world.gdp <- ggplot(world.gdp, aes(x = Year, y = GDP, fill = group)) +
labs(title=paste0("World's Real GDP Growth from 2012-2021")) +
geom_bar(stat = "identity") +
#geom_text(aes(label=GDP), size=4, hjust = 1.2) +
scale_fill_manual(values = c("-" = "red","+" = "limegreen")) +
theme_bw() + theme(legend.position = "none") +
ylab("") +
theme(legend.title=element_blank(),
plot.title = element_text(size=9, face = "bold")
)
gly.world.gdp <- ggplotly(g.world.gdp)
gly.world.gdp
preservef1c232bf28826123
top20.gdp$group <- cut(top20.gdp$GDP,c(-Inf,0,Inf),labels = c("-","+"))
Warning messages:
1: Unknown or uninitialised column: `Country`.
2: Unknown or uninitialised column: `Country`.
3: Unknown or uninitialised column: `Country`.
g.gdp <- top20.gdp %>%
ggplot(aes(x = GDP, y = reorder(country, -ranking), fill = group)) +
labs(title=paste0("Real GDP Growth of top 20 countries from 2019-2020")) +
geom_bar(stat = "identity") +
geom_text(aes(label=GDP), size=4, hjust = 1.2) +
scale_fill_manual(values = c("-" = "red","+" = "limegreen")) +
theme_bw() + theme(legend.position = "none") +
ylab("") +
theme(legend.title=element_blank(),
plot.title = element_text(size=9, face = "bold")
)
g.gdp

data.latest.all
Warning messages:
1: Unknown or uninitialised column: `Country`.
2: Unknown or uninitialised column: `Country`.
3: Unknown or uninitialised column: `Country`.
4: Unknown or uninitialised column: `Country`.
#Top 20 with gdp
data.longGDP <- df_gdp %>% gather(key=year, value=GDP, -c(country))
data.top <- data.latest %>% filter(country!='World'& country!='Others')
#data.top <- head(data.top,20)
#View(data.top)
data.gdp <- filter(data.longGDP,year=='2020') %>% select(country, year,GDP)
#View(data.gdp)
#merge
mergcountry = function(data1,data2){
data <- merge(x = data1, y = data2, by = "country", all.x = TRUE)
return(data)
}
data.top.world <- merge(x = data.top, y = df_gdp2019, by = "country", all.x = TRUE) %>%
select(-c(code,rank,new.confirmed,new.deaths,current.confirmed,population)) %>%
rename(GDP="GDP (millions of US dollars)")
data.top.world <- merge(x = data.top.world, y = df_healt, by = "country", all.x = TRUE) %>%
rename(healthcare="healthCareIndex")
data.top.world <- merge(x = data.top.world, y = df_temp, by = "country", all.x = TRUE)
#data.top.world <- mergcountry(data.top.world, df_temp)
#View(data.top.world)
normalize = function(data){
#return ((data - min(data,na.rm = TRUE))/(max(data,na.rm = TRUE) - min(data,na.rm = TRUE)))
z <- scale(data);
tanh(z/2)
}
norm_data = as.data.frame(apply(data.top.world[,2:10],2,normalize))
corr_data <- norm_data
norm_data$country <- c("Argentina","Bangladesh","Brazil","Chile","Colombia","France","Germany","India","Iran","Italy","Mexico","Pakistan","Peru","Russia","saudi Arabia","South Africa","Spain","Turkey","United Kingdom","US")
#View(norm_data)
norm_data_plot <- select(norm_data,"country","confirm.rate","death.rate","recover.rate","healthcare","GDP", "avg_temp")
norm_data_plot %<>% gather(key=type, value=count, -c(country))
level_order <- factor(norm_data_plot$type,
level = c("avg_temp","GDP","healthcare","recover.rate","death.rate","confirm.rate"))
ggplot(data = norm_data_plot, aes(x = country, y=level_order, fill=count)) +
geom_tile() +
scale_fill_gradient(low = "pink", high = "blue") +
xlab("") +
ylab("") +
theme_bw() +
theme(axis.text.x = element_text(angle = 90,vjust = 1))+
theme(
axis.line = element_blank(),
axis.ticks = element_blank(),
panel.grid.minor = element_blank(),
panel.grid.major = element_blank(),
panel.border = element_blank(),
panel.background = element_blank(),
#legend.position = "none"
)

NA
#correlation
corr_data %<>% select(c(GDP,confirm.rate,death.rate,recover.rate,healthcare,avg_temp))
head(corr_data)
cor(corr_data)
GDP confirm.rate death.rate recover.rate healthcare avg_temp
GDP 1.00000000 0.4297936 -0.2360041 -0.3765615 0.25183938 -0.05173909
confirm.rate 0.42979357 1.0000000 -0.3345825 -0.6868148 0.45433811 -0.38068330
death.rate -0.23600410 -0.3345825 1.0000000 0.1626707 -0.14700200 0.39857475
recover.rate -0.37656150 -0.6868148 0.1626707 1.0000000 -0.75497920 0.29830952
healthcare 0.25183938 0.4543381 -0.1470020 -0.7549792 1.00000000 -0.06716339
avg_temp -0.05173909 -0.3806833 0.3985748 0.2983095 -0.06716339 1.00000000
ggcorrplot(cor(corr_data),hc.order = TRUE,
outline.color = "white",
colors = c("#6D9EC1","white","#E46726"),
lab = TRUE)

LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KI2luc3RhbGwucGFja2FnZXMoImdyaWQiKQ0KI2luc3RhbGwucGFja2FnZXMoIk1MUk1QQSIpDQojaW5zdGFsbC5wYWNrYWdlcygiZHByZXAiKQ0KI2luc3RhbGwucGFja2FnZXMoIm5vcm1hbHIiKQ0KI2luc3RhbGwucGFja2FnZXMoImdnY29ycnBsb3QiKQ0KI2luc3RhbGwucGFja2FnZXMoIlJDb2xvckJyZXdlciIpDQojaW5zdGFsbC5wYWNrYWdlcygicmdkYWwiKQ0KI2luc3RhbGwucGFja2FnZXMoImpzb25saXRlIikNCiNpbnN0YWxsLnBhY2thZ2VzKCJwbG90bHkiKQ0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShncmlkRXh0cmEpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KG1hZ3JpdHRyKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KG5vcm1hbHIpDQpsaWJyYXJ5KGdnY29ycnBsb3QpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KHBsb3RseSkNCiNsaWJyYXJ5KGpzb25saXRlKQ0KI2xpYnJhcnkoUkNvbG9yQnJld2VyKQ0KI2xpYnJhcnkocmdkYWwpDQojbGlicmFyeSh3ZXNhbmRlcnNvbikNCiNsaWJyYXJ5KE1MUk1QQSkNCg0KIz8/c3JjX215c3FsDQpteV9kYiA8LSBzcmNfbXlzcWwoDQogIGRibmFtZSA9ICJjb3ZpZCIsDQogIGhvc3QgPSAibG9jYWxob3N0IiwNCiAgdXNlciA9ICJyb290IiwNCiAgcGFzc3dvcmQgPSAiMTIzNCINCikNCm15X2RiDQoNCiMjaW1wb3J0IGRhdGENCmRmX2NvbmYgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWRfY29uZmlybWVkX3llYXJseSIpKQ0KZGZfY29uZiA8LSBhcy5kYXRhLmZyYW1lKGRmX2NvbmYpDQpkZl9jb25mDQpkZl9kZWF0aHMgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gY292aWRfZGVhdGhzX3llYXJseSIpKQ0KZGZfZGVhdGhzIDwtIGFzLmRhdGEuZnJhbWUoZGZfZGVhdGhzKQ0KZGZfZGVhdGhzDQpkZl9yZWNvdmVyIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGNvdmlkX3JlY292ZXJlZF95ZWFybHkiKSkNCmRmX3JlY292ZXIgPC0gYXMuZGF0YS5mcmFtZShkZl9yZWNvdmVyKQ0KZGZfcmVjb3Zlcg0KYGBgDQpgYGB7cn0NCiMjY2hlY2sgdGhlIHRpbWUgZnJhbWUgb2YgdGhlIGRhdGENCm4uY29sIDwtIG5jb2woZGZfY29uZikNCmRhdGVzIDwtIG5hbWVzKGRmX2NvbmYpWzU6bi5jb2xdJT4lIG1keSgpDQpyYW5nZShkYXRlcykNCm1pbi5kYXRlIDwtIG1pbihkYXRlcykNCm1heC5kYXRlIDwtIG1heChkYXRlcykNCm1pbi5kYXRlLnR4dCA8LSBtaW4uZGF0ZSAlPiUgZm9ybWF0KCclZCAlYiAlWScpDQptYXguZGF0ZS50eHQgPC0gbWF4LmRhdGUgJT4lIGZvcm1hdCgnJWQgJWIgJVknKQ0KYGBgDQpgYGB7cn0NCiNjbGVhbiBkYXRhDQpjbGVhbkRhdGEgPC0gZnVuY3Rpb24oZGF0YSkgew0KICAjIyByZW1vdmUgc29tZSBjb2x1bW5zDQogIGRhdGEgJTw+JSBzZWxlY3QoLWMoUHJvdmluY2UuU3RhdGUsIExhdCwgTG9uZykpICU+JSByZW5hbWUoY291bnRyeT1Db3VudHJ5LlJlZ2lvbikNCiAgIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCiAgZGF0YSAlPD4lIGdhdGhlcihrZXk9ZGF0ZSwgdmFsdWU9Y291bnQsIC1jb3VudHJ5KQ0KICAjIyBjb252ZXJ0IGZyb20gY2hhcmFjdGVyIHRvIGRhdGUNCiAgZGF0YSAlPD4lIG11dGF0ZShkYXRlID0gZGF0ZSAlPiUgbWR5KCkpDQogICMjIGFnZ3JlZ2F0ZSBieSBjb3VudHJ5DQogIGRhdGEgJTw+JSBncm91cF9ieShjb3VudHJ5LCBkYXRlKSAlPiUgc3VtbWFyaXNlKGNvdW50PXN1bShjb3VudCwgbmEucm09VCkpICU+JSBhcy5kYXRhLmZyYW1lKCkNCiAgcmV0dXJuKGRhdGEpDQp9DQojIyBjbGVhbiB0aGUgdGhyZWUgZGF0YSBzZXRzDQpkYXRhLmNvbmZpcm1lZCA8LSBkZl9jb25mICU+JSBjbGVhbkRhdGEoKSAlPiUgcmVuYW1lKGNvbmZpcm1lZD1jb3VudCkNCmRhdGEuZGVhdGhzIDwtIGRmX2RlYXRocyAlPiUgY2xlYW5EYXRhKCkgJT4lIHJlbmFtZShkZWF0aHM9Y291bnQpDQpkYXRhLnJlY292ZXJlZCA8LSBkZl9yZWNvdmVyICU+JSBjbGVhbkRhdGEoKSAlPiUgcmVuYW1lKHJlY292ZXJlZD1jb3VudCkNCmRhdGEgPC0gZGF0YS5jb25maXJtZWQgJT4lIG1lcmdlKGRhdGEuZGVhdGhzLCBhbGw9VCkgJT4lIG1lcmdlKGRhdGEucmVjb3ZlcmVkLCBhbGw9VCkNCmRhdGENCiMjIGNvdW50cmllcy9yZWdpb25zIHdpdGggY29uZmlybWVkIGNhc2VzLCBleGNsLiBjcnVpc2Ugc2hpcHMNCmNvdW50cmllcyA8LSBkYXRhICU+JSBwdWxsKGNvdW50cnkpICU+JSBzZXRkaWZmKCdDcnVpc2UgU2hpcCcpDQpkYXRhDQoNCmRhdGEud29ybGQgPC0gZGF0YSAlPiUgZ3JvdXBfYnkoZGF0ZSkgJT4lDQogIHN1bW1hcmlzZShjb3VudHJ5PSdXb3JsZCcsDQogICAgICAgICAgICBjb25maXJtZWQgPSBzdW0oY29uZmlybWVkLCBuYS5ybT1UKSwNCiAgICAgICAgICAgIGRlYXRocyA9IHN1bShkZWF0aHMsIG5hLnJtPVQpLA0KICAgICAgICAgICAgcmVjb3ZlcmVkID0gc3VtKHJlY292ZXJlZCwgbmEucm09VCkpDQpkYXRhICU8PiUgcmJpbmQoZGF0YS53b3JsZCkNCmRhdGENCmRhdGEgJTw+JSBtdXRhdGUoY3VycmVudC5jb25maXJtZWQgPSBjb25maXJtZWQgLSBkZWF0aHMgLSByZWNvdmVyZWQpDQpWaWV3KGRhdGEpDQoNCmBgYA0KDQpgYGB7cn0NCiNXb3JsZCBNYXAgKHdpdGggU3RhdGUpDQojc2VsZWN0IGxhc3QgY29sdW1uLHdoaWNoIGlzIHRoZSBudW1iZXIgb2YgbGF0ZXN0IGNvbmZpcm1lZCBjYXNlcw0KeCA8LSBkZl9jb25mDQp4DQp4JGNvbmZpcm1lZCA8LSB4WywgbmNvbCh4KV0NCnggJTw+JSBzZWxlY3QoYyhDb3VudHJ5LlJlZ2lvbiwgUHJvdmluY2UuU3RhdGUsIExhdCwgTG9uZywgY29uZmlybWVkKSkgJT4lDQogIG11dGF0ZSh0eHQ9cGFzdGUwKENvdW50cnkuUmVnaW9uLCAnIC0gJywgUHJvdmluY2UuU3RhdGUsICc6ICcsIGNvbmZpcm1lZCkpDQoNCm0gPC0gbGVhZmxldCh3aWR0aD0xMjAwLCBoZWlnaHQ9ODAwKSAlPiUgYWRkVGlsZXMoKQ0KIyBjaXJjbGUgbWFya2VyICh1bml0cyBpbiBwaXhlbHMpDQptICU8PiUgYWRkQ2lyY2xlTWFya2Vycyh4JExvbmcsIHgkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgcmFkaXVzPTErbG9nMih4JGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICAjcmFkaXVzPTAuMDEqc3FydCh4JGNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yPSdyZWQnLCBmaWxsT3BhY2l0eT0wLjMsDQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IHgkdHh0DQogICAgICAgICAgICAgICAgICAgICAgICAjcG9wdXA9eCR0eHQNCiAgICAgICAgICAgICAgICAgICAgICAgICkNCiMgd29ybGQNCm0NCmBgYA0KYGBge3J9DQojVmlldyhsYXQubG9uZykNCm0uY29uZmlybWVkIDwtIGRhdGEgJT4lDQogIHNlbGVjdChjb3VudHJ5LCBkYXRlLCBjb25maXJtZWQpICU+JQ0KICBtZXJnZSgobGF0LmxvbmcgJT4lIHNlbGVjdChjb3VudHJ5LCBMYXQsIExvbmcpKSwgYnkgPSAiY291bnRyeSIpICU+JSANCiAgYXJyYW5nZShjb3VudHJ5LCBkYXRlKQ0KbS5jb25maXJtZWQNCmBgYA0KDQoNCmBgYHtyfQ0KI3JhdGUNCmRhdGEgJTw+JSBhcnJhbmdlKGNvdW50cnksIGRhdGUpDQpuIDwtIG5yb3coZGF0YSkNCmRheTEgPC0gbWluKGRhdGEkZGF0ZSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBjb25maXJtZWQgLSBsYWcoY29uZmlybWVkLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LmRlYXRocyA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCBkZWF0aHMgLSBsYWcoZGVhdGhzLCBuPTEpKSwNCiAgICAgICAgICAgICAgICAgbmV3LnJlY292ZXJlZCA9IGlmZWxzZShkYXRlID09IGRheTEsIE5BLCByZWNvdmVyZWQgLSBsYWcocmVjb3ZlcmVkLCBuPTEpKSkNCmRhdGEgJTw+JSBtdXRhdGUobmV3LmNvbmZpcm1lZCA9IGlmZWxzZShuZXcuY29uZmlybWVkIDwgMCwgMCwgbmV3LmNvbmZpcm1lZCksDQogICAgICAgICAgICAgICAgIG5ldy5kZWF0aHMgPSBpZmVsc2UobmV3LmRlYXRocyA8IDAsIDAsIG5ldy5kZWF0aHMpLA0KICAgICAgICAgICAgICAgICBuZXcucmVjb3ZlcmVkID0gaWZlbHNlKG5ldy5yZWNvdmVyZWQgPCAwLCAwLCBuZXcucmVjb3ZlcmVkKSkNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdG90YWwgZGVhdGhzIGFuZCByZWNvdmVyZWQgY2FzZXMNCmRhdGEgJTw+JSBtdXRhdGUocmF0ZS51cHBlciA9ICgxMDAgKiBkZWF0aHMgLyAoZGVhdGhzICsgcmVjb3ZlcmVkKSkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLnVwcGVyID0gaWZlbHNlKGlzLm5hbihyYXRlLnVwcGVyKSwgMCwgcmF0ZS51cHBlcikpDQoNCiMjIGxvd2VyIGJvdW5kOiBkZWF0aCByYXRlIGJhc2VkIG9uIHRvdGFsIGNvbmZpcm1lZCBjYXNlcw0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmxvd2VyID0gKDEwMCAqIGRlYXRocyAvIGNvbmZpcm1lZCkgJT4lIHJvdW5kKDEpLA0KICAgICAgICAgICAgICAgICByYXRlLmxvd2VyID0gaWZlbHNlKGlzLm5hbihyYXRlLmxvd2VyKSwgMCwgcmF0ZS5sb3dlcikpDQoNCiMjIGRlYXRoIHJhdGUgYmFzZWQgb24gdGhlIG51bWJlciBvZiBkZWF0aC9yZWNvdmVyZWQgb24gZXZlcnkgc2luZ2xlIGRheQ0KZGF0YSAlPD4lIG11dGF0ZShyYXRlLmRhaWx5ID0gKDEwMCAqIG5ldy5kZWF0aHMgLyAobmV3LmRlYXRocyArIG5ldy5yZWNvdmVyZWQpKSAlPiUgcm91bmQoMSksDQogICAgICAgICAgICAgICAgIHJhdGUuZGFpbHkgPSBpZmVsc2UoaXMubmFuKHJhdGUuZGFpbHkpLCAwLCByYXRlLmRhaWx5KSkNCg0KVmlldyhkYXRhKQ0KYGBgDQoNCmBgYHtyfQ0KIyMgY29udmVydCBmcm9tIHdpZGUgdG8gbG9uZyBmb3JtYXQNCmRhdGEubG9uZyA8LSBkYXRhICU+JQ0KICBzZWxlY3QoYyhjb3VudHJ5LCBkYXRlLCBjb25maXJtZWQsIGN1cnJlbnQuY29uZmlybWVkLCByZWNvdmVyZWQsIGRlYXRocykpICU+JQ0KICBnYXRoZXIoa2V5PXR5cGUsIHZhbHVlPWNvdW50LCAtYyhjb3VudHJ5LCBkYXRlKSkNCiMjIHNldCBmYWN0b3IgbGV2ZWxzIHRvIHNob3cgdGhlbSBpbiBhIGRlc2lyYWJsZSBvcmRlcg0KZGF0YS5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLCBjb25maXJtZWQ9J1RvdGFsIENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY29uZmlybWVkPSdDdXJyZW50IENvbmZpcm1lZCcsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXJlZD0nUmVjb3ZlcmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdEZWF0aHMnKSkNClZpZXcoZGF0YS5sb25nKQ0KYGBgDQoNCmBgYHtyfQ0Kd29ybGQNCiMjTnVtYmVyIG9mIGNhc2UgV29ybGQNCndvcmxkIDwtIGZpbHRlcihkYXRhLmxvbmcsY291bnRyeSA9PSAnV29ybGQnKQ0KcGxvdDEgPC0gd29ybGQgJT4lIGZpbHRlcih0eXBlICE9ICdUb3RhbCBDb25maXJtZWQnKSAlPiUNCiAgZ2dwbG90KGFlcyh4PWRhdGUsIHk9Y291bnQpKSArDQogIGdlb21fYXJlYShhZXMoZmlsbD10eXBlKSwgYWxwaGE9MC41KSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENhc2VzIFdvcmxkd2lkZSAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoJ3JlZCcsICdncmVlbicsICdibGFjaycpKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj0nYm90dG9tJywNCiAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQua2V5LnNpemU9dW5pdCgwLjIsICdjbScpLA0KICAgICAgICBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT02KSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTcpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDIgPC0gd29ybGQgJT4lDQogIGdncGxvdChhZXMoeD1kYXRlLCB5PWNvdW50KSkgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yPXR5cGUpKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCdOdW1iZXJzIG9mIENhc2VzIFdvcmxkd2lkZSAobG9nIHNjYWxlKSAtICcsIG1heC5kYXRlLnR4dCkpICsNCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCdwdXJwbGUnLCAncmVkJywgJ2dyZWVuJywgJ2JsYWNrJykpICsNCiAgdGhlbWUobGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLA0KICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIGxlZ2VuZC5rZXkuc2l6ZT11bml0KDAuMiwgJ2NtJyksDQogICAgICAgIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTYpLA0KICAgICAgICBheGlzLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9NyksDQogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zPSdsb2cxMCcpDQojIyBzaG93IHR3byBwbG90cyBzaWRlIGJ5IHNpZGUNCmdyaWQuYXJyYW5nZShwbG90MSwgcGxvdDIsIG5jb2w9MikNCmBgYA0KYGBge3J9DQojIyBDdXJyZW50IENvbmZpcm1lZCBDYXNlcw0KZGF0YS53b3JsZCA8LSBkYXRhICU+JSBmaWx0ZXIoY291bnRyeT09J1dvcmxkJykNCm4gPC0gbnJvdyhkYXRhLndvcmxkKQ0KcGxvdDEgPC0gZ2dwbG90KGRhdGEud29ybGQsIGFlcyh4PWRhdGUsIHk9Y3VycmVudC5jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdDdXJyZW50IENvbmZpcm1lZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkgDQpnbHkucGxvdDEgPC0gZ2dwbG90bHkocGxvdDEpDQoNCnBsb3QyIDwtIGdncGxvdChkYXRhLndvcmxkLCBhZXMoeD1kYXRlLCB5PW5ldy5jb25maXJtZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdEYWlseSBOZXcgQ29uZmlybWVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSANCmdseS5wbG90MiA8LSBnZ3Bsb3RseShwbG90MikNCiMjIHNob3cgdHdvIHBsb3RzIHNpZGUgYnkgc2lkZQ0KZ3JpZC5hcnJhbmdlKHBsb3QxLCBwbG90MiwgbmNvbD0yKQ0KI3N1YnBsb3QoZ2x5LnBsb3QxLCBnbHkucGxvdDIpDQpgYGANCmBgYHtyfQ0KIyMgYSBzY2F0dGVyIHBsb3Qgd2l0aCBhIHNtb290aGVkIGxpbmUgYW5kIHZlcnRpY2FsIHgtYXhpcyBsYWJlbHMNCnBsb3QxIDwtIGdncGxvdChkYXRhLndvcmxkLCBhZXMoeD1kYXRlLCB5PWRlYXRocykpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J0FjY3VtdWxhdGl2ZSBEZWF0aHMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90MiA8LSBnZ3Bsb3QoZGF0YS53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1yZWNvdmVyZWQpKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkgKw0KICB4bGFiKCcnKSArIHlsYWIoJ0NvdW50JykgKyBsYWJzKHRpdGxlPSdBY2N1bXVsYXRpdmUgUmVjb3ZlcmVkIENhc2VzJykgKw0KICB0aGVtZShheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKQ0KcGxvdDMgPC0gZ2dwbG90KGRhdGEud29ybGQsIGFlcyh4PWRhdGUsIHk9bmV3LmRlYXRocykpICsNCiAgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgoKSArDQogIHhsYWIoJycpICsgeWxhYignQ291bnQnKSArIGxhYnModGl0bGU9J05ldyBEZWF0aHMnKSArDQogIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpDQpwbG90NCA8LSBnZ3Bsb3QoZGF0YS53b3JsZCwgYWVzKHg9ZGF0ZSwgeT1uZXcucmVjb3ZlcmVkKSkgKw0KICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aCgpICsNCiAgeGxhYignJykgKyB5bGFiKCdDb3VudCcpICsgbGFicyh0aXRsZT0nTmV3IFJlY292ZXJlZCBDYXNlcycpICsNCiAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSkNCiMjIHNob3cgZm91ciBwbG90cyB0b2dldGhlciwgd2l0aCAyIHBsb3RzIGluIGVhY2ggcm93DQpncmlkLmFycmFuZ2UocGxvdDEsIHBsb3QyLCBwbG90MywgcGxvdDQsIG5yb3c9MikNCmBgYA0KDQoNCg0KYGBge3J9DQojIyBjb252ZXJ0IGZyb20gd2lkZSB0byBsb25nIGZvcm1hdCwgZm9yIGRyYXdpbmcgYXJlYSBwbG90cw0KcmF0ZXMubG9uZyA8LSBkYXRhICU+JQ0KICBzZWxlY3QoYyhjb3VudHJ5LCBkYXRlLCByYXRlLnVwcGVyLCByYXRlLmxvd2VyLCByYXRlLmRhaWx5KSkgJT4lDQogIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jKGNvdW50cnksIGRhdGUpKQ0KIyBzZXQgZmFjdG9yIGxldmVscyB0byBzaG93IHRoZW0gaW4gYSBkZXNpcmFibGUgb3JkZXINCnJhdGVzLmxvbmcgJTw+JSBtdXRhdGUodHlwZT1yZWNvZGVfZmFjdG9yKHR5cGUsIHJhdGUuZGFpbHkgPSAiRGFpbHkiLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICByYXRlLnVwcGVyPSJVcHBlciBib3VuZCIsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJhdGUubG93ZXIgPSAiTG93ZXIgYm91bmQiKQ0KICAgICAgICAgICAgICAgICAgICAgICkNCg0KZy5kZWF0aCA8LSByYXRlcy5sb25nICU+JSBmaWx0ZXIoY291bnRyeSA9PSAiV29ybGQiKSAlPiUgcmVuYW1lKGMoIlJhdGUiID0gImNvdW50IiwgIkRhdGUiID0gImRhdGUiLCAiVHlwZSIgPSAidHlwZSIpKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gRGF0ZSwgeSA9IFJhdGUpKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCJEZWF0aCBDYXNlcyAmIERlYXRoIFJhdGVzIiksIHN1YnRpdGxlID0gIkRlYXRoIENhc2VzICYgRGVhdGggUmF0ZXMgaW4gVG9wIDIwIENvdW50cmllcyAoJSkgKDIwMjApIikgKw0KICBnZW9tX2xpbmUoYWVzKGNvbG9yID0gVHlwZSkpICsgDQogICNzdGF0X3Ntb290aChhZXMoY29sb3IgPSB0eXBlKSkNCiAgI3N0YXRfc21vb3RoKGFlcyh4ID0gZGF0ZSwgeSA9IGNvdW50KSwgbWV0aG9kID0gImxtIiwgZm9ybXVsYSA9IHkgfiBwb2x5KHgsIDIxKSwgc2UgPSBGQUxTRSkgKw0KICB0aGVtZSgNCiAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplPTEyKSwNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgICAgICkgKw0KICB4bGFiKCJEYXRlIikgKyB5bGFiKCJSYXRlcyAoJSkiKQ0KDQpnbHkuZGVhdGggPC0gZ2dwbG90bHkoZy5kZWF0aCkNCmdseS5kZWF0aA0KYGBgDQoNCmBgYHtyfQ0KIyMgcmFua2luZyBieSBjb25maXJtZWQgY2FzZXMNCmRhdGEubGF0ZXN0LmFsbCA8LSBkYXRhICU+JSBmaWx0ZXIoZGF0ZSA9PSBtYXgoZGF0ZSkpICU+JQ0KICBzZWxlY3QoY291bnRyeSwgZGF0ZSxjb25maXJtZWQsIG5ldy5jb25maXJtZWQsIGN1cnJlbnQuY29uZmlybWVkLA0KICAgICAgICAgcmVjb3ZlcmVkLCBkZWF0aHMsIG5ldy5kZWF0aHMsIGRlYXRoLnJhdGU9cmF0ZS5sb3dlcikgJT4lDQogIG11dGF0ZShyYW5raW5nID0gZGVuc2VfcmFuayhkZXNjKGNvbmZpcm1lZCkpKSAlPiUNCiAgYXJyYW5nZShyYW5raW5nKQ0KVmlldyhkYXRhLmxhdGVzdC5hbGwpDQoNCmsgPC0gMjANCiMjIHRvcCAyMCBjb3VudHJpZXM6IDIxIGluY2wuICdXb3JsZCcNCnRvcC5jb3VudHJpZXMgPC0gZGF0YS5sYXRlc3QuYWxsICU+JSBmaWx0ZXIocmFua2luZyA8PSBrICsgMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykgJT4lIHB1bGwoY291bnRyeSkgJT4lIGFzLmNoYXJhY3RlcigpDQp0b3AuY291bnRyaWVzICU+JSBzZXRkaWZmKCdXb3JsZCcpICU+JSBwcmludCgpDQpgYGANCg0KYGBge3J9DQpkYXRhLmxhdGVzdCA8LSBkYXRhLmxhdGVzdC5hbGwgJT4lIGZpbHRlcighaXMubmEoY291bnRyeSkpICU+JQ0KICBtdXRhdGUoY291bnRyeT1pZmVsc2UocmFua2luZyA8PSBrICsgMSwgYXMuY2hhcmFjdGVyKGNvdW50cnkpLCAnT3RoZXJzJykpICU+JQ0KICBtdXRhdGUoY291bnRyeT1jb3VudHJ5ICU+JSBmYWN0b3IobGV2ZWxzPWModG9wLmNvdW50cmllcywgJ090aGVycycpKSkNCmRhdGEubGF0ZXN0ICU8PiUgZ3JvdXBfYnkoY291bnRyeSkgJT4lDQogIHN1bW1hcmlzZShjb25maXJtZWQ9c3VtKGNvbmZpcm1lZCksIG5ldy5jb25maXJtZWQ9c3VtKG5ldy5jb25maXJtZWQpLA0KICAgICAgICAgICAgY3VycmVudC5jb25maXJtZWQ9c3VtKGN1cnJlbnQuY29uZmlybWVkKSwNCiAgICAgICAgICAgIHJlY292ZXJlZD1zdW0ocmVjb3ZlcmVkKSwgZGVhdGhzPXN1bShkZWF0aHMpLCBuZXcuZGVhdGhzPXN1bShuZXcuZGVhdGhzKSkgJT4lDQogIG11dGF0ZShkZWF0aC5yYXRlPSgxMDAgKiBkZWF0aHMvY29uZmlybWVkKSAlPiUgcm91bmQoMSkpIA0KZGF0YS5sYXRlc3QNCmRhdGEubGF0ZXN0ICU8PiUgc2VsZWN0KGMoY291bnRyeSwgY29uZmlybWVkLCBkZWF0aHMsIGRlYXRoLnJhdGUsDQogICAgICAgICAgICAgICAgICAgICAgICAgIG5ldy5jb25maXJtZWQsIG5ldy5kZWF0aHMsIGN1cnJlbnQuY29uZmlybWVkLHJlY292ZXJlZCkpICU+JQ0KICBtdXRhdGUocmVjb3Zlci5yYXRlPSgxMDAgKiByZWNvdmVyZWQvY29uZmlybWVkKSAlPiUgcm91bmQoMSkpDQpkYXRhLmxhdGVzdA0KDQpkZl9wb3AgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gcG9wdWxhdGlvbiAiKSkNCmRmX3BvcCA8LSBhcy5kYXRhLmZyYW1lKGRmX3BvcCkNCmRmX3BvcCA8LSByZW5hbWUoZGZfcG9wLCJjb3VudHJ5Ij0iQ291bnRyeSIpDQoNCiMgQWRkIFdvcmxkIFBvcHVsYXRpb24NCndvcmxkX3BvcCA8LSBzdW0oZGZfcG9wJGBQb3B1bGF0aW9uICgyMDIwKWApDQpkZl9wb3BbbnJvdyhkZl9wb3ApICsgMSxdID0gYygiV29ybGQiLCB3b3JsZF9wb3ApDQoNCiMgQWRkIE90aGVyIENvdW50cmllcyBQb3B1bGF0aW9uDQp0b3BfcG9wIDwtIGZpbHRlcihkZl9wb3AsIGRmX3BvcCRjb3VudHJ5ICVpbiUgdG9wLmNvdW50cmllcyAmIGRmX3BvcCRjb3VudHJ5ICE9ICJXb3JsZCIpDQp0b3BfcG9wIDwtIHN1bSh0b3BfcG9wJGBQb3B1bGF0aW9uICgyMDIwKWAgJT4lIGFzLm51bWVyaWMoKSkNCm90aGVyc19wb3AgPC0gKHdvcmxkX3BvcCAtIHRvcF9wb3ApIA0KZGZfcG9wW25yb3coZGZfcG9wKSArIDEsXSA9IGMoIk90aGVycyIsIG90aGVyc19wb3ApDQojVmlldyhkZl9wb3ApDQoNCmRhdGEubGF0ZXN0IDwtIG1lcmdlKHggPSBkYXRhLmxhdGVzdCwgeSA9IGRmX3BvcCwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgDQpkYXRhLmxhdGVzdA0KZGF0YS5sYXRlc3QgPC0gcmVuYW1lKGRhdGEubGF0ZXN0LCJwb3B1bGF0aW9uIiA9ICJQb3B1bGF0aW9uICgyMDIwKSIpDQpkYXRhLmxhdGVzdCRwb3B1bGF0aW9uIDwtIGRhdGEubGF0ZXN0JHBvcHVsYXRpb24gJT4lIGFzLm51bWVyaWMoKQ0KZGF0YS5sYXRlc3QgIDwtIGRhdGEubGF0ZXN0ICU+JQ0KICBzZWxlY3QoYyhjb3VudHJ5LCBjb25maXJtZWQsIGRlYXRocywgZGVhdGgucmF0ZSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3LmNvbmZpcm1lZCwgbmV3LmRlYXRocywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudC5jb25maXJtZWQsIHJlY292ZXJlZCwgcmVjb3Zlci5yYXRlLCBwb3B1bGF0aW9uKSkgJT4lDQogIG11dGF0ZShjb25maXJtLnJhdGUgPSAoMTAwICogY29uZmlybWVkIC8gcG9wdWxhdGlvbikgJT4lIHJvdW5kKDEpKQ0KZGF0YS5sYXRlc3QNCmBgYA0KYGBge3J9DQpkYXRhLmxhdGVzdCAlPiUgbXV0YXRlKGRlYXRoLnJhdGU9ZGVhdGgucmF0ZSAlPiUgZm9ybWF0KG5zbWFsbD0xKSAlPiUgcGFzdGUwKCclJykpDQoNCmBgYA0KDQpgYGB7cn0NCiMjIGNvbnZlcnQgZnJvbSB3aWRlIHRvIGxvbmcgZm9ybWF0LCBmb3IgZHJhd2luZyBhcmVhIHBsb3RzDQpkYXRhLmxhdGVzdC5sb25nIDwtIGRhdGEubGF0ZXN0ICU+JSBmaWx0ZXIoY291bnRyeSE9J1dvcmxkJykgJT4lDQogIGdhdGhlcihrZXk9dHlwZSwgdmFsdWU9Y291bnQsIC1jb3VudHJ5KQ0KIyMgc2V0IGZhY3RvciBsZXZlbHMgdG8gc2hvdyB0aGVtIHdpdGggcHJvcGVyIHRleHQgYW5kIGluIGEgZGVzaXJhYmxlIG9yZGVyDQpkYXRhLmxhdGVzdC5sb25nICU8PiUgbXV0YXRlKHR5cGU9cmVjb2RlX2ZhY3Rvcih0eXBlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlybWVkPSdUb3RhbCBDb25maXJtZWQnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGhzPSdUb3RhbCBEZWF0aHMnLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVhdGgucmF0ZT0nRGVhdGggUmF0ZSAoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3LmNvbmZpcm1lZD0nTmV3IENvbmZpcm1lZCAoY29tcGFyZWQgd2l0aCBvbmUgZGF5IGJlZm9yZSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3LmRlYXRocz0nTmV3IERlYXRocyAoY29tcGFyZWQgd2l0aCBvbmUgZGF5IGJlZm9yZSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VycmVudC5jb25maXJtZWQ9J0N1cnJlbnQgQ29uZmlybWVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlY292ZXIucmF0ZSA9ICdSZWNvdmVyIFJhdGUoJSknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uZmlybS5yYXRlID0gJ0NvbmZpcm1lZCBSYXRlKCUpJykpDQojVmlldyhkYXRhLmxhdGVzdC5sb25nKQ0KZGF0YS5vbmUuZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdUb3RhbCBDb25maXJtZWQnDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J1RvdGFsIERlYXRocycNCiAgICAgICAgICAgICAgICAgICAgICAgfCB0eXBlPT0nQ3VycmVudCBDb25maXJtZWQnKQ0KZGF0YS50d28uZGVtIDwtIGZpbHRlcihkYXRhLmxhdGVzdC5sb25nLHR5cGU9PSdEZWF0aCBSYXRlICglKScNCiAgICAgICAgICAgICAgICAgICAgICAgfCB0eXBlPT0nTmV3IENvbmZpcm1lZCAoY29tcGFyZWQgd2l0aCBvbmUgZGF5IGJlZm9yZSknDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J05ldyBEZWF0aHMgKGNvbXBhcmVkIHdpdGggb25lIGRheSBiZWZvcmUpJw0KICAgICAgICAgICAgICAgICAgICAgICB8IHR5cGU9PSdSZWNvdmVyIFJhdGUoJSknDQogICAgICAgICAgICAgICAgICAgICAgIHwgdHlwZT09J0NvbmZpcm1lZCBSYXRlKCUpJykNCmRhdGEudHdvLmRlbQ0KYGBgDQoNCmBgYHtyfQ0KIyMgYmFyIGNoYXJ0DQpkYXRhLm9uZS5kZW0gJT4lIGdncGxvdChhZXMoeD1jb3VudHJ5LCB5PWNvdW50LCBmaWxsPWNvdW50cnksIGdyb3VwPWNvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50LCB5PWNvdW50KSwgc2l6ZT0zLCB2anVzdD0wKSArDQogIHhsYWIoJycpICsgeWxhYignJykgKw0KICBsYWJzKHRpdGxlPXBhc3RlMCgnVG9wIDIwIENvdW50cmllcyB3aXRoIE1vc3QgQ29uZmlybWVkIENhc2VzIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9J0NvdW50cnknLCBsYWJlbHM9YWVzKGNvdW50KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzKSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIGZhY2V0X3dyYXAofnR5cGUsIG5jb2w9MSwgc2NhbGVzPSdmcmVlX3knKQ0KDQpgYGANCmBgYHtyfQ0KDQpkYXRhLnR3by5kZW0gJT4lIGdncGxvdChhZXMoeD1jb3VudHJ5LCB5PWNvdW50LCBmaWxsPWNvdW50cnksIGdyb3VwPWNvdW50cnkpKSArDQogIGdlb21fYmFyKHN0YXQ9J2lkZW50aXR5JykgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPWNvdW50LCB5PWNvdW50KSwgc2l6ZT0zLCB2anVzdD0wKSArDQogIHhsYWIoJycpICsgeWxhYignJykgKw0KICBsYWJzKHRpdGxlPXBhc3RlMCgnVG9wIDIwIENvdW50cmllcyB3aXRoIE1vc3QgQ29uZmlybWVkIENhc2VzIC0gJywgbWF4LmRhdGUudHh0KSkgKw0KICBzY2FsZV9maWxsX2Rpc2NyZXRlKG5hbWU9J0NvdW50cnknLCBsYWJlbHM9YWVzKGNvdW50KSkgKw0KICB0aGVtZShsZWdlbmQudGl0bGU9ZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBsZWdlbmQucG9zaXRpb249J25vbmUnLA0KICAgICAgICBwbG90LnRpdGxlPWVsZW1lbnRfdGV4dChzaXplPTEzKSwNCiAgICAgICAgYXhpcy50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTgpLA0KICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpKSArDQogIGZhY2V0X3dyYXAofnR5cGUsIG5jb2w9MSwgc2NhbGVzPSdmcmVlX3knKQ0KYGBgDQoNCmBgYHtyfQ0KIyNHRFANCmRmX2dkcCA8LSB0YmwobXlfZGIsIHNxbCgic2VsZWN0ICogZnJvbSBnZHAiKSkNCmRmX2dkcCA8LSBhcy5kYXRhLmZyYW1lKGRmX2dkcCkNCmRmX2dkcCA8LSByZW5hbWUoZGZfZ2RwLCJjb3VudHJ5Ij0iUmVhbCBHRFAgZ3Jvd3RoIChBbm51YWwgcGVyY2VudCBjaGFuZ2UpIikNCmRmX2dkcCA8LSBzZWxlY3QoZGZfZ2RwLGMoImNvdW50cnkiLCIyMDEyIiwiMjAxMyIsIjIwMTQiLCIyMDE1IiwiMjAxNiIsIjIwMTciLCIyMDE4IiwiMjAxOSIsIjIwMjAiLCIyMDIxIikpDQpkZl9nZHANCmRmX2dkcDIwMTkgPC0gdGJsKG15X2RiLCBzcWwoInNlbGVjdCAqIGZyb20gZ2RwMTkiKSkNCmRmX2dkcDIwMTkgPC0gYXMuZGF0YS5mcmFtZShkZl9nZHAyMDE5KQ0KZGZfZ2RwMjAxOQ0KDQpgYGANCmBgYHtyfQ0KI2hlYWx0aHJhbmtpbmcNCmRmX2hlYWx0IDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIGhlYWx0aHJhbmtpbmciKSkNCmRmX2hlYWx0IDwtIGFzLmRhdGEuZnJhbWUoZGZfaGVhbHQpDQpkZl9oZWFsdCA8LSBzZWxlY3QoZGZfaGVhbHQsYygiY291bnRyeSIsImhlYWx0aENhcmVJbmRleCIpKQ0KVmlldyhkZl9oZWFsdCkNCmBgYA0KDQpgYGB7cn0NCiN0ZW1wDQpkZl90ZW1wIDwtIHRibChteV9kYiwgc3FsKCJzZWxlY3QgKiBmcm9tIHdvcmxkX3RlbXAiKSkNCmRmX3RlbXAgPC0gYXMuZGF0YS5mcmFtZShkZl90ZW1wKSANCmRmX3RlbXAkQ291bnRyeVtkZl90ZW1wJENvdW50cnkgPT0gIlVuaXRlZCBTdGF0ZXMiXSA8LSAiVVMiDQoNCmRmX2NpdHkgPC0gc2VsZWN0KGRmX3RlbXAsYygiQ291bnRyeSIsIkNpdHkiKSkgJT4lDQogIHJlbmFtZShjb3VudHJ5PUNvdW50cnkpICU+JSANCiAgcmVuYW1lKGNpdHk9Q2l0eSkNCg0KbnVtb2ZjaXR5IDwtIGFnZ3JlZ2F0ZShjaXR5IH4gY291bnRyeSwgZGF0YSA9IGRmX2NpdHksIGxlbmd0aCkNCg0KZGZfdGVtcCA8LSBzZWxlY3QoZGZfdGVtcCxjKCJDb3VudHJ5IiwiQXZnX1llYXIiKSkgJT4lDQogIHJlbmFtZShjb3VudHJ5PUNvdW50cnkpDQpWaWV3KGRmX3RlbXApDQoNCiNkZl90ZW1wIDwtIGRhdGEuZnJhbWUoY291bnRyeT1kZl90ZW1wWywxXSxhdmc9cm93TWVhbnMoZGZfdGVtcFssLTFdKSkNCmRmX3RlbXAgPC0gZGZfdGVtcCAlPD4lIGdyb3VwX2J5KGNvdW50cnkpICU+JSBzdW1tYXJpc2UoYXZnX3RlbXAgPSBtZWFuKEF2Z19ZZWFyLG5hLnJtID0gVFJVRSklPiUgcm91bmQoMSkpDQpkZl90ZW1wDQpgYGANCmBgYHtyfQ0KI2Rpc3BsYXkuYnJld2VyLmFsbCgpDQpkZl90ZW1wLmFsbCA8LSBkZl90ZW1wICAlPiUgbWVyZ2UoZGF0YS5sYXRlc3QuYWxsKQ0KVmlldyhkZl90ZW1wLmFsbCkNCmRmX3RlbXBfdG9wLmFsbCA8LSBkZl90ZW1wLmFsbCAlPiUgZmlsdGVyKGNvdW50cnkgJWluJSB0b3AuY291bnRyaWVzKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNClZpZXcoZGZfdGVtcF90b3ApDQpnX3RlbXBfdG9wIDwtIGRmX3RlbXBfdG9wICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSByZW9yZGVyKGNvdW50cnksIHJhbmtpbmcpLCB5ID0gYXZnX3RlbXAsIGZpbGwgPSBhdmdfdGVtcCkpICsNCiAgbGFicyh0aXRsZT1wYXN0ZTAoIlRlbXBlcmF0dXJlIGluIFRvcCAgMjAgY291bnRyaWVzIiksIHN1YnRpdGxlID0gIkF2ZXJhZ2UgVGVtcGVyYXR1cmUgaW4gVG9wIDIwIGNvdW50cmllcyB3aXRoIG1vc3QgY29uZmlybWVkIGNhc2VzICjCsEMpICgyMDIwKSIpICsNCiAgc2NhbGVfY29sb3JfZ3JhZGllbnQobG93ID0gIiM5M0RCRkYiLCBoaWdoID0gIiNGRjc3NzEiKSArDQogIGdlb21fdGV4dChhZXMobGFiZWw9YXZnX3RlbXAsIHk9YXZnX3RlbXApLCBzaXplPTQsIHZqdXN0PS0wLjUpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKw0KICB0aGVtZSgNCiAgICAgICAgbGVnZW5kLnRpdGxlPWVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSdub25lJywNCiAgICAgICAgcGxvdC50aXRsZT1lbGVtZW50X3RleHQoc2l6ZSA9IDE1LCBoanVzdCA9IDAuNSksDQogICAgICAgIHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSksDQogICAgICAgIGF4aXMudGV4dD1lbGVtZW50X3RleHQoc2l6ZT04KSwNCiAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KHNpemUgPSA5LCBhbmdsZT00NSwgaGp1c3Q9MSkpICsNCiAgeGxhYigiQ291bnRyeSIpICsgeWxhYigiQXZlcmFnZSBUZW1wZXJhdHVyZSIpDQogIA0KICAjc2NhbGVfeF9kaXNjcmV0ZShuYW1lID0gIkNvdW50cnkiKSArDQogICNzY2FsZV95X2Rpc2NyZXRlKG5hbWUgPSAiQXZlcmFnZSBUZW1wZXJhdHVyZSIpDQoNCiAgICAgICAgICAgI2xhYnModGl0bGUgPSAiVGVtcGVyYXR1cmUgaW4gVG9wICAyMCBjb3VudHJpZXMiLCBzdWJ0aXRsZSA9ICJUZW1wZXJhdHVyZSBpbiBUb3AgMjAgY291bnRyaWVzIHdpdGggbW9zdCBjb25maXJtZWQgY2FzZXMgKMKwQykiKQ0KICAgICAgICAgDQojZ190ZW1wX3RvcCAgICAgICAgIA0KZ190ZW1wX3RvcCANCg0KYGBgDQoNCg0KYGBge3J9DQojZGZfY29uZg0KI2RhdGEubGF0ZXN0LmFsbA0KbGF0LmxvbmcgPC0gcmVuYW1lKGRmX2NvbmYsICJjb3VudHJ5IiA9ICJDb3VudHJ5LlJlZ2lvbiIsICJjaXR5IiA9ICJQcm92aW5jZS5TdGF0ZSIpICU+JSANCiAgc2VsZWN0KCJjb3VudHJ5IiwgIkxhdCIsICJMb25nIikgJT4lIA0KICBtZXJnZShkZl90ZW1wLmFsbFtjKCJjb3VudHJ5IiwiY29uZmlybWVkIiwgInJlY292ZXJlZCIsICJkZWF0aHMiLCAiYXZnX3RlbXAiLCAicmFua2luZyIpXSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBkaXN0aW5jdChjb3VudHJ5LCAua2VlcF9hbGwgPSBUUlVFKSAlPiUNCiAgbXV0YXRlKHJhbmtpbmcgPSByYW5raW5nIC0gMSkgJT4lDQogIGFycmFuZ2UocmFua2luZykNClZpZXcobGF0LmxvbmcpDQpgYGANCmBgYHtyfQ0KbGFiZWxfd29ybGQgPC0gbGF0LmxvbmcgDQpsYWJlbF93b3JsZCRhdmdfdGVtcCA8LSBhcy5udW1lcmljKGxhYmVsX3dvcmxkWywgbmFtZXMobGFiZWxfd29ybGQpICVpbiUgYygiYXZnX3RlbXAiKV0pDQpsYWJlbF93b3JsZCA8LSBsYWJlbF93b3JsZCAlPiUgIA0KICBtdXRhdGUodHh0PXBhc3RlMCgnPGI+JyxyYW5raW5nLCAnPC9iPicsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsJzxiPicsY291bnRyeSwgJzwvYj4nLA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiVGVtcGVyYXR1cmU6ICAiLGF2Z190ZW1wLCAnIMKwQycsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJDb25maXJtZWQ6ICAiLCBjb25maXJtZWQsIA0KICAgICAgICAgICAgICAgICAgICAnPGJyLz4nLCAiRGVhdGhzOiAiLCBkZWF0aHMsDQogICAgICAgICAgICAgICAgICAgICc8YnIvPicsICJSZWNvdmVyZWQ6ICIsIHJlY292ZXJlZA0KICAgICAgICAgICAgICAgICAgICApKSANCg0KbGFiZWxfd29ybGQkdHh0IDwtIGxhYmVsX3dvcmxkJHR4dCAlPiUgbGFwcGx5KGh0bWx0b29sczo6SFRNTCkNCmxhYmVsX3dvcmxkIA0KDQpsYWJlbF90b3AgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nIDwgMjEpDQpsYWJlbF90b3ANCmBgYA0KDQpgYGB7cn0NCndwYWwgPC0gY29sb3JOdW1lcmljKCJZbE9yUmQiLCBsYWJlbF93b3JsZCRhdmdfdGVtcCwgbiA9IDUpDQoNCnRvcEljb24gPC0gbWFrZUljb24oInN0YXIucG5nIiwNCiAgI2ljb25VcmwgPSAiaHR0cHM6Ly9zdGF0aWMudmVjdGVlenkuY29tL3N5c3RlbS9yZXNvdXJjZXMvcHJldmlld3MvMDAxLzE4OS8wNjMvbm9uXzJ4L3N0YXItcm91bmRlZC1wbmcucG5nIiwNCiAgaWNvbldpZHRoID0gMTAsIGljb25IZWlnaHQgPSAxMA0KICAjaWNvbkFuY2hvclggPSAyMCwgaWNvbkFuY2hvclkgPSAyMA0KICANCikNCg0KbGFiZWxfd29ybGQgPC0gbGFiZWxfd29ybGQgJT4lIGZpbHRlcihyYW5raW5nID4gMjApIA0KICANCm0gPC0gbGVhZmxldCh3aWR0aD0xMjAwLCBoZWlnaHQ9ODAwKSAlPiUgYWRkVGlsZXMoKSAgDQptICU8PiUgIGFkZENpcmNsZU1hcmtlcnMobGFiZWxfd29ybGQkTG9uZywgbGFiZWxfd29ybGQkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF93b3JsZCRhdmdfdGVtcCksIA0KICAgICAgICAgICAgICAgICAgICAgICAgZmlsbE9wYWNpdHk9MC41LA0KICAgICAgICAgICAgICAgICAgICAgICAgI3BvcHVwPWxhYmVsLnRvcCR0eHQNCiAgICAgICAgICAgICAgICAgICAgICAgIGxhYmVsPSBsYWJlbF93b3JsZCR0eHQsDQogICAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJXb3JsZCINCiAgICAgICAgICAgICAgICAgICAgICAgICkgJT4lDQogIA0KICBhZGRDaXJjbGVNYXJrZXJzKGxhYmVsX3RvcCRMb25nLCBsYWJlbF90b3AkTGF0LA0KICAgICAgICAgICAgICAgICAgICAgICAgIyByYWRpdXM9Mitsb2cyKHgkY29uZmlybWVkKSwNCiAgICAgICAgICAgICAgICAgICAgICAgIHJhZGl1cz0xMCwjKmxvZzIobS53b3JsZCRhdmcudGVtcCksDQogICAgICAgICAgICAgICAgICAgICAgICBzdHJva2U9RiwNCiAgICAgICAgICAgICAgICAgICAgICAgICNjb2xvcj0ncmVkJywNCiAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gd3BhbChsYWJlbF90b3AkYXZnX3RlbXApLCANCiAgICAgICAgICAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5PTAuNSwNCiAgICAgICAgICAgICAgICAgICAgICAgICNwb3B1cD1sYWJlbC50b3AkdHh0DQogICAgICAgICAgICAgICAgICAgICAgICBsYWJlbD0gbGFiZWxfdG9wJHR4dCwNCiAgICAgICAgICAgICAgICAgICAgICAgIGdyb3VwID0gIlRvcCAyMCBDb3VudHJpZXMiDQogICAgICAgICAgICAgICAgICAgICAgICApICU+JQ0KICANCiAgYWRkTGFiZWxPbmx5TWFya2VycyhsYWJlbF90b3AkTG9uZywgbGFiZWxfdG9wJExhdCwgbGFiZWwgPSBsYWJlbF90b3AkcmFua2luZywNCiAgICAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMobm9IaWRlID0gVFJVRSwgdGV4dE9ubHkgPSBUUlVFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlyZWN0aW9uID0gImhlYWQiLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gYyg1LDQpKSwNCiAgICAgICAgICAgICAgICAgICAgICBncm91cCA9ICJUb3AgMjAgQ291bnRyaWVzIikgJT4lDQogIA0KICBhZGRMZWdlbmQoImJvdHRvbXJpZ2h0IiwgcGFsID0gd3BhbCwgdmFsdWVzID0gbGFiZWxfd29ybGQkYXZnX3RlbXAsIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gbGFiZWxGb3JtYXQoc3VmZml4ID0gJyDCsEMnKSwNCiAgICAgICAgICAgIHRpdGxlID0gIlRlbXBlcmF0dXJlIikgJT4lIA0KICANCiAgYWRkTGF5ZXJzQ29udHJvbCgNCiAgICAjYmFzZUdyb3VwcyA9IGMoIk9TTSAoZGVmYXVsdCkiLCAiVG9uZXIiLCAiVG9uZXIgTGl0ZSIpLA0KICAgIG92ZXJsYXlHcm91cHMgPSBjKCJUb3AgMjAgQ291bnRyaWVzIiwgIldvcmxkIiksDQogICAgb3B0aW9ucyA9IGxheWVyc0NvbnRyb2xPcHRpb25zKGNvbGxhcHNlZCA9IEZBTFNFKQ0KICApDQptDQoNCmBgYA0KDQpgYGB7cn0NCmRhdGEuZ2RwDQojcmFuayBHRFANCmRhdGEudG9wLmhpZ2h0IDwtIGRhdGEuZ2RwICU+JQ0KICBtdXRhdGUocmFua2luZyA9IGRlbnNlX3JhbmsoZGVzYyhHRFApKSkNCmRhdGEudG9wLmhpZ2h0DQprIDwtIDE1DQp0b3AuZ2RwIDwtIGRhdGEudG9wLmhpZ2h0ICU+JSANCiAgI2ZpbHRlcihyYW5raW5nIDw9IGsgKyAxKSAlPiUgDQogIGFycmFuZ2UocmFua2luZykNCnRvcC5nZHAgPC0gaGVhZCh0b3AuZ2RwLDIxKQ0KDQpkYXRhLnRvcC5sb3cgPC0gZGF0YS5nZHAgJT4lDQogIG11dGF0ZShyYW5raW5nID0gZGVuc2VfcmFuayhHRFApKQ0KbG93LmdkcC5sb25nIDwtIGRhdGEudG9wLmxvdyAlPiUgDQogICNmaWx0ZXIocmFua2luZyA8PSBrICsgMSkgJT4lIA0KICBhcnJhbmdlKHJhbmtpbmcpDQojVmlldyhsb3cuZ2RwLmxvbmcpDQpsb3cuZ2RwIDwtIGhlYWQobG93LmdkcC5sb25nLDIzKQ0KDQp0b3AyMC5nZHAgPC0gZGF0YS5nZHAgJT4lIA0KICBmaWx0ZXIoY291bnRyeSAlaW4lIHRvcC5jb3VudHJpZXMgJiBjb3VudHJ5ICE9ICJXb3JsZCIpICU+JQ0KICBtZXJnZShkYXRhLmxhdGVzdC5hbGwgJT4lIHNlbGVjdChjb3VudHJ5LCByYW5raW5nKSwgYnkgPSAiY291bnRyeSIpICU+JQ0KICBtdXRhdGUocmFua2luZyA9IHJhbmtpbmcgLSAxKSAlPiUNCiAgYXJyYW5nZShyYW5raW5nKQ0KICANCnRvcC5nZHANCmxvdy5nZHANCnRvcDIwLmdkcA0KYGBgDQpgYGB7cn0NCndvcmxkLmdkcCA8LSBkZl9nZHAgJT4lIA0KICBmaWx0ZXIoY291bnRyeSA9PSAiV29ybGQiKSAlPiUgDQogIGdhdGhlcihrZXkgPSBZZWFyLCB2YWx1ZSA9IEdEUCwgLWNvdW50cnkpIA0Kd29ybGQuZ2RwJGdyb3VwIDwtIGN1dCh3b3JsZC5nZHAkR0RQLGMoLUluZiwwLEluZiksbGFiZWxzID0gYygiLSIsIisiKSkNCg0KZy53b3JsZC5nZHAgPC0gZ2dwbG90KHdvcmxkLmdkcCwgYWVzKHggPSBZZWFyLCB5ID0gR0RQLCBmaWxsID0gZ3JvdXApKSArDQogIGxhYnModGl0bGU9cGFzdGUwKCJXb3JsZCdzIFJlYWwgR0RQIEdyb3d0aCBmcm9tIDIwMTItMjAyMSIpKSArDQogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArDQogICNnZW9tX3RleHQoYWVzKGxhYmVsPUdEUCksIHNpemU9NCwgaGp1c3QgPSAxLjIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiLSIgPSAicmVkIiwiKyIgPSAibGltZWdyZWVuIikpICsNCiAgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICB5bGFiKCIiKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05LCBmYWNlID0gImJvbGQiKQ0KICAgICkNCg0KZ2x5LndvcmxkLmdkcCA8LSBnZ3Bsb3RseShnLndvcmxkLmdkcCkgDQpnbHkud29ybGQuZ2RwDQpgYGANCg0KYGBge3J9DQp0b3AyMC5nZHAkZ3JvdXAgPC0gY3V0KHRvcDIwLmdkcCRHRFAsYygtSW5mLDAsSW5mKSxsYWJlbHMgPSBjKCItIiwiKyIpKQ0KZy5nZHAgPC0gdG9wMjAuZ2RwICU+JQ0KICBnZ3Bsb3QoYWVzKHggPSBHRFAsIHkgPSByZW9yZGVyKGNvdW50cnksIC1yYW5raW5nKSwgZmlsbCA9IGdyb3VwKSkgKw0KICBsYWJzKHRpdGxlPXBhc3RlMCgiUmVhbCBHRFAgR3Jvd3RoIG9mIHRvcCAyMCBjb3VudHJpZXMgZnJvbSAyMDE5LTIwMjAiKSkgKw0KICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKw0KICBnZW9tX3RleHQoYWVzKGxhYmVsPUdEUCksIHNpemU9NCwgaGp1c3QgPSAxLjIpICsNCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gYygiLSIgPSAicmVkIiwiKyIgPSAibGltZWdyZWVuIikpICsNCiAgdGhlbWVfYncoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKw0KICB5bGFiKCIiKSArDQogIHRoZW1lKGxlZ2VuZC50aXRsZT1lbGVtZW50X2JsYW5rKCksDQogICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT05LCBmYWNlID0gImJvbGQiKQ0KICAgICkNCmcuZ2RwDQpgYGANCg0KYGBge3J9DQpkYXRhLmxhdGVzdC5hbGwNCiNUb3AgMjAgd2l0aCBnZHANCmRhdGEubG9uZ0dEUCA8LSBkZl9nZHAgJT4lIGdhdGhlcihrZXk9eWVhciwgdmFsdWU9R0RQLCAtYyhjb3VudHJ5KSkNCmRhdGEudG9wIDwtIGRhdGEubGF0ZXN0ICU+JSBmaWx0ZXIoY291bnRyeSE9J1dvcmxkJyYgY291bnRyeSE9J090aGVycycpDQojZGF0YS50b3AgPC0gaGVhZChkYXRhLnRvcCwyMCkNCiNWaWV3KGRhdGEudG9wKQ0KZGF0YS5nZHAgPC0gZmlsdGVyKGRhdGEubG9uZ0dEUCx5ZWFyPT0nMjAyMCcpICU+JSBzZWxlY3QoY291bnRyeSwgeWVhcixHRFApDQojVmlldyhkYXRhLmdkcCkNCiNtZXJnZQ0KbWVyZ2NvdW50cnkgPSBmdW5jdGlvbihkYXRhMSxkYXRhMil7DQogIGRhdGEgPC0gbWVyZ2UoeCA9IGRhdGExLCB5ID0gZGF0YTIsIGJ5ID0gImNvdW50cnkiLCBhbGwueCA9IFRSVUUpIA0KICByZXR1cm4oZGF0YSkNCn0NCmRhdGEudG9wLndvcmxkIDwtIG1lcmdlKHggPSBkYXRhLnRvcCwgeSA9IGRmX2dkcDIwMTksIGJ5ID0gImNvdW50cnkiLCBhbGwueCA9IFRSVUUpICU+JSANCiAgc2VsZWN0KC1jKGNvZGUscmFuayxuZXcuY29uZmlybWVkLG5ldy5kZWF0aHMsY3VycmVudC5jb25maXJtZWQscG9wdWxhdGlvbikpICU+JSANCiAgcmVuYW1lKEdEUD0iR0RQIChtaWxsaW9ucyBvZiBVUyBkb2xsYXJzKSIpDQpkYXRhLnRvcC53b3JsZCA8LSBtZXJnZSh4ID0gZGF0YS50b3Aud29ybGQsIHkgPSBkZl9oZWFsdCwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgJT4lDQogIHJlbmFtZShoZWFsdGhjYXJlPSJoZWFsdGhDYXJlSW5kZXgiKQ0KZGF0YS50b3Aud29ybGQgPC0gbWVyZ2UoeCA9IGRhdGEudG9wLndvcmxkLCB5ID0gZGZfdGVtcCwgYnkgPSAiY291bnRyeSIsIGFsbC54ID0gVFJVRSkgDQojZGF0YS50b3Aud29ybGQgPC0gbWVyZ2NvdW50cnkoZGF0YS50b3Aud29ybGQsIGRmX3RlbXApDQojVmlldyhkYXRhLnRvcC53b3JsZCkNCm5vcm1hbGl6ZSA9IGZ1bmN0aW9uKGRhdGEpew0KICAjcmV0dXJuICgoZGF0YSAtIG1pbihkYXRhLG5hLnJtID0gVFJVRSkpLyhtYXgoZGF0YSxuYS5ybSA9IFRSVUUpIC0gbWluKGRhdGEsbmEucm0gPSBUUlVFKSkpDQogIHogPC0gc2NhbGUoZGF0YSk7DQogIHRhbmgoei8yKQ0KfQ0Kbm9ybV9kYXRhID0gYXMuZGF0YS5mcmFtZShhcHBseShkYXRhLnRvcC53b3JsZFssMjoxMF0sMixub3JtYWxpemUpKQ0KY29ycl9kYXRhIDwtIG5vcm1fZGF0YQ0Kbm9ybV9kYXRhJGNvdW50cnkgPC0gYygiQXJnZW50aW5hIiwiQmFuZ2xhZGVzaCIsIkJyYXppbCIsIkNoaWxlIiwiQ29sb21iaWEiLCJGcmFuY2UiLCJHZXJtYW55IiwiSW5kaWEiLCJJcmFuIiwiSXRhbHkiLCJNZXhpY28iLCJQYWtpc3RhbiIsIlBlcnUiLCJSdXNzaWEiLCJzYXVkaSBBcmFiaWEiLCJTb3V0aCBBZnJpY2EiLCJTcGFpbiIsIlR1cmtleSIsIlVuaXRlZCBLaW5nZG9tIiwiVVMiKQ0KI1ZpZXcobm9ybV9kYXRhKQ0Kbm9ybV9kYXRhX3Bsb3QgPC0gc2VsZWN0KG5vcm1fZGF0YSwiY291bnRyeSIsImNvbmZpcm0ucmF0ZSIsImRlYXRoLnJhdGUiLCJyZWNvdmVyLnJhdGUiLCJoZWFsdGhjYXJlIiwiR0RQIiwgImF2Z190ZW1wIikNCm5vcm1fZGF0YV9wbG90ICU8PiUgZ2F0aGVyKGtleT10eXBlLCB2YWx1ZT1jb3VudCwgLWMoY291bnRyeSkpDQpsZXZlbF9vcmRlciA8LSBmYWN0b3Iobm9ybV9kYXRhX3Bsb3QkdHlwZSwgDQogICAgICAgICAgICAgICAgICAgICAgbGV2ZWwgPSBjKCJhdmdfdGVtcCIsIkdEUCIsImhlYWx0aGNhcmUiLCJyZWNvdmVyLnJhdGUiLCJkZWF0aC5yYXRlIiwiY29uZmlybS5yYXRlIikpDQoNCg0KZ2dwbG90KGRhdGEgPSBub3JtX2RhdGFfcGxvdCwgYWVzKHggPSBjb3VudHJ5LCB5PWxldmVsX29yZGVyLCBmaWxsPWNvdW50KSkgKyANCiAgZ2VvbV90aWxlKCkgKw0KICBzY2FsZV9maWxsX2dyYWRpZW50KGxvdyA9ICJwaW5rIiwgaGlnaCA9ICJibHVlIikgKw0KICB4bGFiKCIiKSArDQogIHlsYWIoIiIpICsNCiAgdGhlbWVfYncoKSArDQogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsdmp1c3QgPSAxKSkrDQogIHRoZW1lKA0KICAgIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLA0KICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X2JsYW5rKCksDQogICAgcGFuZWwuYmFja2dyb3VuZCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAjbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiDQogICkNCiAgDQpgYGANCg0KDQoNCg0KYGBge3J9DQojY29ycmVsYXRpb24NCmNvcnJfZGF0YSAlPD4lIHNlbGVjdChjKEdEUCxjb25maXJtLnJhdGUsZGVhdGgucmF0ZSxyZWNvdmVyLnJhdGUsaGVhbHRoY2FyZSxhdmdfdGVtcCkpDQpoZWFkKGNvcnJfZGF0YSkNCmNvcihjb3JyX2RhdGEpDQpnZ2NvcnJwbG90KGNvcihjb3JyX2RhdGEpLGhjLm9yZGVyID0gVFJVRSwNCiAgICAgICAgICAgb3V0bGluZS5jb2xvciA9ICJ3aGl0ZSIsDQogICAgICAgICAgIGNvbG9ycyA9IGMoIiM2RDlFQzEiLCJ3aGl0ZSIsIiNFNDY3MjYiKSwNCiAgICAgICAgICAgbGFiID0gVFJVRSkNCmBgYA0KDQoNCg0K